import { TreeNode } from './TreeNode';
import { ElementType } from '../config';

/**
 * 数据节点
 */
export class DataNode extends TreeNode {
  static context = {
    getRaw: (key) => null,
    getType: (key) => null,
    getIn: (key) => null,
    setIn: (key, val) => { },
    getOut: (key) => null,
    setOut: (key, val) => { },
    setBranchOut: (key, branchIndex, val) => { },
    addRaw: (raw) => { },
    deleteRaw: (key) => { },
  };

  static DataNodeMap = new Map();

  constructor(key) {
    super();
    this._key = key;
    if (key) {
      DataNode.DataNodeMap.set(key, this);
    }
  }

  _key;

  get key() {
    return this._key;
  }

  get raw() {
    return DataNode.context.getRaw(this.key);
  }

  get type() {
    return DataNode.context.getType(this.key);
  }

  get in() {
    return DataNode.context.getIn(this.key);
  }

  set in(val) {
    DataNode.context.setIn(this.key, val);
  }

  get out() {
    return DataNode.context.getOut(this.key);
  }

  set out(val) {
    // 条件节点 - 额外工作
    if (this.type === ElementType.CONDITION) {
      // 当前操作node存在的分支
      let branchIndex = -1;
      // 当前操作node在分支中位置
      let branchNodeIndex = -1;
      this.getChildren().some((child, childIndex) => {
        const grandChildIndex = child.getChildren().findIndex((grandChild) => grandChild.key === val);

        if (grandChildIndex != -1) {
          branchIndex = childIndex;
          branchNodeIndex = grandChildIndex;
          return true;
        }
        return false;
      });

      // 如果操作的节点不在分支中，则设置condition的out
      if (branchIndex == -1) {
        DataNode.context.setOut(this.key, val);
      }

      this.getChildren().some((child, childIndex) => {
        const branch = child;
        const branchChildren = branch.getChildren();

        if (branchNodeIndex == 0 && branchIndex == childIndex) {
          branch.out = val;
          return true;
        } else if (branchIndex == -1 && branchChildren.length == 0) {
          branch.out = val;
          return false;
        } else if (branchChildren.length > 0) {
          const last = branchChildren[branchChildren.length - 1];
          last.out = val;
        }

        return false;
      });
    } else {
      DataNode.context.setOut(this.key, val);
    }
  }

  getParent() {
    return super.getParent();
  }

  getChildren() {
    return super.getChildren();
  }

  setBranchOut(branchIndex, val) {
    DataNode.context.setBranchOut(this.key, branchIndex, val);
  }

  removeChild(node) {
    super.removeChild(node);
    DataNode.DataNodeMap.delete(node.key);
    DataNode.context.deleteRaw(node.key);
  }
}

/**
 * 分支
 */
export class DataBranch extends DataNode {
  constructor(branchIndex) {
    super(null);
    this._branchIndex = branchIndex;
  }

  _branchIndex;

  get condition() {
    return this.getParent();
  }

  get key() {
    if (!this.condition) {
      return 'root';
    }
    return `${this.condition.key}-${this.branchIndex}`;
  }

  get type() {
    return ElementType.BRANCH;
  }

  get raw() {
    return {
      key: this.key,
      name: this.branch?.conditionName,
      outgoings: [this.out],
      incomings: [this.in],
      elementType: ElementType.BRANCH,
    };
  }

  get branchIndex() {
    return this._branchIndex;
  }

  get branch() {
    const parent = this.getParent();
    return parent?.raw.conditions?.[this._branchIndex];
  }

  get in() {
    const parent = this.getParent();
    return parent?.key;
  }

  set in(_val) { }

  get out() {
    return this.branch?.outgoing;
  }

  set out(val) {
    this.condition.setBranchOut(this._branchIndex, val);
  }

  getParent() {
    return super.getParent();
  }

  getChildren() {
    return super.getChildren();
  }
} 